package com.web.exiaodao.business.service.impl;

import com.alibaba.fastjson.JSON;
import com.alipay.PayService;
import com.web.exiaodao.business.constant.JConstant;
import com.web.exiaodao.business.entity.Order;
import com.web.exiaodao.business.entity.Returnshoprecord;
import com.web.exiaodao.business.repository.OrderRepository;
import com.web.exiaodao.business.repository.ReturnshoprecordRepository;
import com.web.exiaodao.business.service.ReturnshoprecordService;
import com.web.exiaodao.remote.service.ApiOrderService;
import com.web.exiaodao.remote.vo.OrderVo;
import com.web.exiaodao.remote.vo.ReturnshoprecordVo;
import com.web.webstart.base.constant.XaConstant;
import com.web.webstart.base.exception.BusinessException;
import com.web.webstart.base.service.impl.BaseService;
import com.web.webstart.base.util.DateUtils;
import com.web.webstart.base.util.Identities;
import com.web.webstart.base.util.SqlResultUtil;
import com.web.webstart.base.util.XaUtil;
import com.web.webstart.base.util.jpa.MyPage;
import com.web.webstart.base.util.jpa.SearchFilter;
import com.web.webstart.base.util.jpa.SearchFilter.Operator;
import com.web.webstart.base.util.result.XaResult;
import com.wxpay.PayReqRefundData;
import com.wxpay.common.Signature;
import com.wxpay.common.XMLParser;
import com.wxpay.config.WxpayConfig;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import static com.web.exiaodao.business.constant.JConstant.OrderRefundStatus.REFUNDFAIL;
import static com.web.exiaodao.business.constant.JConstant.OrderRefundStatus.REFUNDSUCESS;
import static com.web.exiaodao.business.constant.JConstant.OrderRefundStatus.REFUND_SUCCESS;
import static com.web.exiaodao.business.constant.JConstant.SERVER_ADDRESS;
import static com.web.exiaodao.business.constant.JConstant.SERVER_NAME;

@Service("ReturnshoprecordService")
@Transactional(readOnly = false)
public class ReturnshoprecordServiceImpl extends BaseService<ReturnshoprecordVo> implements ReturnshoprecordService {

    private static final Logger LOGGER = Logger.getLogger(ReturnshoprecordServiceImpl.class);

    @Autowired
    private ReturnshoprecordRepository returnshoprecordRepository;

    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private ApiOrderService orderService;

    /**
     * 查询单条Returnshoprecord信息
     * //@param tId
     *
     * @return 返回单个Returnshoprecord对象
     * @throws BusinessException
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public XaResult<ReturnshoprecordVo> findOne(Long modelId) throws BusinessException {
        Returnshoprecord obj = new Returnshoprecord();
        if (modelId != 0) {
            obj = returnshoprecordRepository.findByIdAndStatusNot(modelId, XaConstant.Status.delete);
        }
        XaResult<ReturnshoprecordVo> xr = new XaResult<ReturnshoprecordVo>();
        if (XaUtil.isNotEmpty(obj)) {
            xr.setObject(JSON.parseObject(JSON.toJSONString(obj), ReturnshoprecordVo.class));
            LOGGER.info("后台----->查询单个实体----->Returnshoprecord");
        } else {
            xr.error(XaConstant.Message.object_not_find);
            LOGGER.info(XaConstant.Message.object_not_find);
        }
        return xr;
    }

    /**
     * 分页查询状态非status的Returnshoprecord数据
     *
     * @param status
     * @param filterParams
     * @param pageable
     * @return 返回对象Returnshoprecord集合
     * @throws BusinessException
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public XaResult<Page<ReturnshoprecordVo>> findListNEStatusByFilter(
            Integer status, Map<String, Object> filterParams, Pageable pageable) throws BusinessException {

        int refundStatus = NumberUtils.toInt(filterParams.get("EQ_refundStatus")+"");//退货状态

        Map<String, SearchFilter> filters = SearchFilter.parse(filterParams);
        if (status == null) {// 默认显示非删除的所有数据
            status = XaConstant.Status.delete;
        }
        filters.put("status", new SearchFilter("status", Operator.NE, status));

        filters.remove("EQ_refundStatus");
        String sqlParam = "";
        if (refundStatus != 0) {
            sqlParam = "  AND orders.refund_status = " + refundStatus + " ";
        }
        if (filterParams.get("EQ_orderNo") != null) {
            sqlParam = "  AND orders.order_no = " + filterParams.get("EQ_orderNo") + " ";
        }
        if (filterParams.get("EQ_type") != null) {
            sqlParam = "  AND record.type = " + filterParams.get("EQ_type") + " ";
        }

        /**
         SELECT record.id, record.create_time , record.audit_advice,record.audit_time, record.auditor, record.imgs, record.reason, record.type,
         orders.order_no, orders.order_total_pirce, orders.order_state,orders.payment_kind, orders.user_id,orders.refund_status, orders.user_id,
         users.user_name
         FROM tb_xa_returnshoprecord record
         LEFT JOIN tb_xa_order orders ON record.order_no = orders.order_no
         LEFT JOIN tb_xa_user users   ON orders.user_id = users.id
         WHERE record.status <> 3 AND orders.refund_status = 1
         ORDER BY record.create_time DESC ;
         */

        //联合order进行查询
        String sql = "SELECT record.id, record.create_time ,record.audit_advice,record.audit_time, record.auditor, record.imgs, record.reason, record.type,\n" +
                "     orders.order_no, orders.order_total_pirce, orders.order_state,orders.payment_kind,orders.refund_status, orders.user_id,\n" +
                "     users.user_name\n" +
                "FROM tb_xa_returnshoprecord record\n" +
                "  LEFT JOIN tb_xa_order orders ON record.order_no = orders.order_no\n" +
                "  LEFT JOIN tb_xa_user users   ON orders.user_id = users.id\n " +
                "WHERE record.status <> 3 \n" + sqlParam +
                "ORDER BY record.create_time DESC ";
        int begin = pageable.getPageNumber();
        int count = pageable.getPageSize();

        String countSql = "SELECT count(*)\n" +
                "FROM tb_xa_returnshoprecord record\n" +
                "  LEFT JOIN tb_xa_order orders ON record.order_no = orders.order_no\n" +
                "  LEFT JOIN tb_xa_user users   ON orders.user_id = users.id\n" +
                "WHERE record.status <> 3 " + sqlParam +
                "ORDER BY record.create_time DESC ";

        //查询的列表集合
        List<Object[]> objs = this.queryParams(sql, begin * count, count, null);
        //查询的总条数
        List<Object[]> c = this.queryParams(countSql, null, null, null);
        List<ReturnshoprecordVo> vos = new ArrayList<>();
        for (Object[] obj : objs) {
            ReturnshoprecordVo vo = new ReturnshoprecordVo();
            vo.setId(SqlResultUtil.getSqlResultLong(obj[0]));
            vo.setCreateTime(SqlResultUtil.getSqlResultString(obj[1]));
            vo.setAuditAdvice(SqlResultUtil.getSqlResultString(obj[2]));
            vo.setAuditTime(SqlResultUtil.getSqlResultString(obj[3]));
            vo.setAuditor(SqlResultUtil.getSqlResultString(obj[4]));
            vo.setImgs(SqlResultUtil.getSqlResultString(obj[5]));
            vo.setReason(SqlResultUtil.getSqlResultString(obj[6]));
            vo.setType(SqlResultUtil.getSqlResultInteger(obj[7]));

            OrderVo orderVo = new OrderVo();
            vo.setOrder(orderVo);

            orderVo.setOrderNo(SqlResultUtil.getSqlResultString(obj[8]));
            orderVo.setGoodsTotalPrices(SqlResultUtil.getSqlResultDouble(obj[9]));
            orderVo.setOrderState(SqlResultUtil.getSqlResultString(obj[10]));
            orderVo.setPaymentKind(SqlResultUtil.getSqlResultInteger(obj[11]));
            orderVo.setRefundStatus(SqlResultUtil.getSqlResultInteger(obj[12]));
            orderVo.setUserId(SqlResultUtil.getSqlResultLong(obj[13]));

            vo.setUserName(SqlResultUtil.getSqlResultString(obj[14]));

            vo.setOrderNo(orderVo.getOrderNo());

            vos.add(vo);
        }

        XaResult<Page<ReturnshoprecordVo>> xr = new XaResult<>();
        long rowCount =  SqlResultUtil.getSqlResultLong(c.get(0));
        xr.setObject(new MyPage<>(begin, count, vos, rowCount));

        LOGGER.info("后台----->分页查询实体集合（状态不等于）----->Returnshoprecord");
        return xr;
    }

    /**
     * 分页查询状态status的Returnshoprecord数据
     *
     * @param status
     * @param filterParams
     * @param pageable
     * @return 返回对象Returnshoprecord集合
     * @throws BusinessException
     */
    @Transactional(readOnly = true, rollbackFor = Exception.class)
    public XaResult<Page<ReturnshoprecordVo>> findListEQStatusByFilter(
            Integer status, Map<String, Object> filterParams, Pageable pageable) throws BusinessException {
        throw new BusinessException(XaConstant.Message.object_property_not_find);
    }

    /**
     * 保存Returnshoprecord信息
     *
     * @param model
     * @return
     * @throws BusinessException
     */
    @Transactional(rollbackFor = Exception.class)
    public XaResult<ReturnshoprecordVo> saveOrUpdate(ReturnshoprecordVo model) throws BusinessException {
        Returnshoprecord obj = null;
        if (XaUtil.isNotEmpty(model.getId())) {
            obj = returnshoprecordRepository.findOne(model.getId());
        } else {
            obj = new Returnshoprecord();
        }
        obj.setCreateUser(XaUtil.isNotEmpty(model.getCreateUser()) ? model.getCreateUser() : obj.getCreateUser());
        obj.setOrderNo(XaUtil.isNotEmpty(model.getOrderNo()) ? model.getOrderNo() : obj.getOrderNo());
        obj.setType(XaUtil.isNotEmpty(model.getType()) ? model.getType() : obj.getType());
        obj.setReason(XaUtil.isNotEmpty(model.getReason()) ? model.getReason() : obj.getReason());
        obj.setImgs(XaUtil.isNotEmpty(model.getImgs()) ? model.getImgs() : obj.getImgs());
        obj.setAuditAdvice(XaUtil.isNotEmpty(model.getAuditAdvice()) ? model.getAuditAdvice() : obj.getAuditAdvice());
        obj.setAuditTime(XaUtil.isNotEmpty(model.getAuditTime()) ? model.getAuditTime() : obj.getAuditTime());
        obj.setAuditor(XaUtil.isNotEmpty(model.getAuditor()) ? model.getAuditor() : obj.getAuditor());
        obj = returnshoprecordRepository.save(obj);
        XaResult<ReturnshoprecordVo> xr = new XaResult<>();
        xr.setObject(JSON.parseObject(JSON.toJSONString(obj), ReturnshoprecordVo.class));
        LOGGER.info("后台新增或编辑数据成功！");
        return xr;
    }

    /**
     * 修改Returnshoprecord状态，可一次修改多条   3删除  -1锁定  1正常
     * //@param userId
     *
     * @param modelIds
     * @param status
     * @return 返回Returnshoprecord对象
     * @throws BusinessException
     */
    @Transactional(rollbackFor = Exception.class)
    public XaResult<ReturnshoprecordVo> multiOperate(
            String modelIds, Integer status) throws BusinessException {
        XaResult<ReturnshoprecordVo> xr = new XaResult<ReturnshoprecordVo>();
        if (status == null) {
            status = XaConstant.Status.delete;
        }
        if (modelIds != null) {
            String[] ids = modelIds.split(",");
            for (String id : ids) {
                Returnshoprecord obj = returnshoprecordRepository.findByIdAndStatusNot(Long.parseLong(id), status);
                if (XaUtil.isNotEmpty(obj)) {
                    obj.setStatus(status);
                    obj = returnshoprecordRepository.save(obj);
                }
            }
        }
        LOGGER.info("批量修改数据状态成功！");
        return xr;
    }

    //退款/退货审核
    @Override
    public XaResult<String> auditing(Long id, String auditAdvice, Integer refundStatus, HttpServletRequest request) throws Exception {
        XaResult<String> xr = new XaResult<>();
        Returnshoprecord r = returnshoprecordRepository.findByIdAndStatusNot(id, XaConstant.Status.delete);
        if (XaUtil.isEmpty(r)) {
            xr.error("该退货信息不存在，请选择其他");
            return xr;
        }

        String orderNo = r.getOrderNo();
        Order order = orderRepository.findByOrderNo(orderNo);
        if (XaUtil.isEmpty(r)) {
            xr.error("该退货订单不存在，请选择其他");
            return xr;
        }
        if (REFUND_SUCCESS.intValue() == order.getRefundStatus() || JConstant.OrderRefundStatus.REFUND_FAIL.intValue() == order.getRefundStatus()) {
            LOGGER.info("该退货信息已处理完成，不可重复处理");
            xr.error("该退货信息已处理，不可重复处理(" + order.getRefundStatus() + ")");
        } else {
            //修改订单表
            String updateOrderStatus = "";
            String weixinOrderRefuNo = Identities.getRefuOrderNo();
            if (refundStatus.intValue() == REFUNDSUCESS) {//审核成功
                LOGGER.info("退款订单审核成功！");
                //查询退款的订单信息

                //判断订单的支付方式
                if (order.getPaymentKind() == JConstant.PayType.UNIONPAY) {    //银联
                    xr.error("银联退款暂不支持！");
                    return xr;
                            /*Map<String, String> data = new HashMap<String, String>();
							*//***银联全渠道系统，产品参数，除了encoding自行选择外其他不需修改***//*
							data.put("version", SDKUtil.version);               //版本号
							data.put("encoding", SDKUtil.encoding_UTF8);             //字符集编码 可以使用UTF-8,GBK两种方式
							data.put("signMethod", "01");                        //签名方法 目前只支持01-RSA方式证书加密
							data.put("txnType", "04");                           //交易类型 04-退货
							data.put("txnSubType", "00");                        //交易子类型  默认00
							data.put("bizType", "000501");                       //业务类型 代收
							data.put("channelType", "07");                       //渠道类型，07-PC，08-手机

							*//***商户接入参数***//*
							data.put("merId", BaseConfig.merId);                //商户号码，请改成自己申请的商户号或者open上注册得来的777商户号测试
							data.put("accessType", "0");                         //接入类型，商户接入固定填0，不需修改
							data.put("orderId", order.getRefuOrderNo());          	//商户订单号，8-40位数字字母，不能含“-”或“_”，可以自行定制规则，重新产生，不同于原消费
							data.put("txnTime", DateTools.getTodayStrSimple());      //订单发送时间，格式为YYYYMMDDhhmmss，必须取当前时间，否则会报txnTime无效
							data.put("currencyCode", "156");                     //交易币种（境内商户一般是156 人民币）
							String txnAmt = new java.text.DecimalFormat("0").format(order.getOrderNumber() * order.getOrderPrice() * 100);
							data.put("txnAmt", txnAmt);                          //****退货金额，单位分，不要带小数点。退货金额小于等于原消费金额，当小于的时候可以多次退货至退货累计金额等于原消费金额
							data.put("reqReserved", "透传信息");                    //请求方保留域，透传字段（可以实现商户自定义参数的追踪）本交易的后台通知,对本交易的交易状态查询交易、对账文件中均会原样返回，商户可以按需上传，长度为1-1024个字节
							String backUrl = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/lvchong/api/notice/backUrl";
							data.put("backUrl", backUrl);               //后台通知地址，后台通知参数详见open.unionpay.com帮助中心 下载  产品接口规范  网关支付产品接口规范 退货交易 商户通知,其他说明同消费交易的后台通知

							*//***要调通交易以下字段必须修改***//*
							data.put("origQryId", order.getQueryId());      //****原消费交易返回的的queryId，可以从消费交易后台通知接口中或者交易状态查询接口中获取

							*//**请求参数设置完毕，以下对请求参数进行签名并发送http post请求，接收同步应答报文------------->**//*

							//从classpath加载acp_sdk.properties文件
							String base_url = request.getSession().getServletContext().getRealPath("/");
							SDKConfig.getConfig().loadPropertiesFromPath(null,base_url);

							Map<String, String> submitFromData  = SDKUtil.signData(data,SDKUtil.encoding_UTF8);//报文中certId,signature的值是在signData方法中获取并自动赋值的，只要证书配置正确即可。
							String url = SDKConfig.getConfig().getBackRequestUrl();//交易请求url从配置文件读取对应属性文件acp_sdk.properties中的 acpsdk.backTransUrl
							//如果这里通讯读超时（30秒），需发起交易状态查询交易
							Map<String, String> resmap = SDKUtil.submitUrl(submitFromData, url,SDKUtil.encoding_UTF8);//这里调用signData之后，调用submitUrl之前不能对submitFromData中的键值对做任何修改，如果修改会导致验签不通过
							*//**对应答码的处理，请根据您的业务逻辑来编写程序,以下应答码处理逻辑仅供参考------------->**//*
							//应答码规范参考open.unionpay.com帮助中心 下载  产品接口规范  《平台接入接口规范-第5部分-附录》
							String respCode = resmap.get("respCode") ;
							if(("00").equals(respCode)){
								//交易已受理，等待接收后台通知更新订单状态,也可以主动发起 查询交易确定交易状态。
								System.out.println("交易已受理");
							}else if(("03").equals(respCode)||
									 ("04").equals(respCode)||
									 ("05").equals(respCode)){
								//后续需发起交易状态查询交易确定交易状态
								System.out.println("需后续发起查询");
							}else{
								//其他应答码为失败请排查原因
								System.out.println("交易失败");
							}*/
							/*String reqMessage = DemoBase.genHtmlResult(submitFromData);
							String rspMessage = DemoBase.genHtmlResult(resmap);
							resp.getWriter().write("请求报文:<br/>"+reqMessage+"<br/>" + "应答报文:</br>"+rspMessage+"");*/
                } else if (order.getPaymentKind() == JConstant.PayType.WXPAY) {        //微信
                    LOGGER.info("微信退款开始！");
                    String nonce_str = Identities.generateRandomCharAndNumber(16);
                    PayReqRefundData data = new PayReqRefundData();
                    data.setAppid(WxpayConfig.getAppID());
                    data.setMch_id(WxpayConfig.getMchID());
                    data.setNonce_str(nonce_str);
                    //data.setAttach("深圳分店");
                    data.setOut_trade_no(order.getOrderNo());
                    data.setTotal_fee(Integer.valueOf(new java.text.DecimalFormat("0").format((order.getOrderTotalPirce()) * 100)));
                    data.setRefund_fee(Integer.valueOf(new java.text.DecimalFormat("0").format((order.getOrderTotalPirce()) * 100)));
                    data.setOut_refund_no(weixinOrderRefuNo);
                    data.setOp_user_id(WxpayConfig.getMchID());
                    data.setSign(Signature.getSign(data));
                    //请求数据获取结果
                    String str = com.wxpay.PayService.refund(data);
                    Map<String, Object> map = XMLParser.getMapFromXML(str);
                    System.out.println(map);
                    LOGGER.info(map);
                    //{refund_id=2009632001201606280298151757, refund_fee=2, coupon_refund_fee=0, refund_channel=, return_msg=OK, appid=wx99550a98f932dfbd, nonce_str=fuTWBAO0JVrevavn, out_trade_no=6665856298736523, out_refund_no=6274136360701294, transaction_id=4009632001201606277960173569, coupon_refund_count=0, sign=891E5B5ACEA9D52D87712D8B388C463F, result_code=SUCCESS, mch_id=1341682101, total_fee=2, return_code=SUCCESS, cash_refund_fee=2, cash_fee=2}
                    //退款申请提交成功，结果通过退款查询接口查询，用零钱支付的退款20分钟内到账，银行卡支付的退款3个工作日后重新查询退款状态。
                    if ("SUCCESS".equals(map.get("result_code")) && "SUCCESS".equals(map.get("return_code"))) {
                        System.out.println("退款申请提交成功！");
                        LOGGER.info("退款申请提交成功！");
                        xr.success("退款申请提交成功");
                    }
                } else if (order.getPaymentKind() == JConstant.PayType.ALIPAY) {    //支付宝
                    LOGGER.info("支付宝退款开始！");
                    com.alipay.PayReqRefundData pay = new com.alipay.PayReqRefundData();
                    //批次号，必填，格式：当天日期[8位]+序列号[3至24位]，如：201603081000001
                    pay.setBatch_no(DateUtils.getTodayStrSimple() + Identities.getRandomNumber(5));
                    //退款笔数，必填，参数detail_data的值中，“#”字符出现的数量加1，最大支持1000笔（即“#”字符出现的数量999个）
                    pay.setBatch_num("1");
                    //退款详细数据，必填，格式（支付宝交易号^退款金额^备注），多笔请用#隔开
                    if (XaUtil.isEmpty(order.getQueryId())) {
                        xr.error("支付宝queryId缺失无法退款,请联系客服");
                        return xr;
                    }
                    pay.setDetail_data(order.getQueryId() + "^" + (order.getOrderTotalPirce()) + "^" + "退款");
                    //通知地址
                    String notify_url = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort() + "/" + SERVER_NAME + "/api/alipay/notifyRefund";
                    notify_url = JConstant.ENV == 1 ? notify_url : SERVER_ADDRESS + SERVER_NAME + "/api/alipay/notifyRefund";
                    pay.setNotify_url(notify_url);
                    System.out.println(notify_url);
                    String result = PayService.refundHavePwd(pay);

                    if (XaUtil.isEmpty(result)) {
                        xr.error("支付宝退款失败!");
                        return xr;
                    }
                    LOGGER.info(result);
                    LOGGER.info("支付宝退款提交成功！");
                    xr.success(result);
                } else  if (order.getPaymentKind() == JConstant.PayType.WALLET) {
                    orderService.modifyOrderRefund(orderNo, REFUND_SUCCESS, JConstant.PayType.WALLET);
                    LOGGER.info("钱包退款完成！！");
                    xr.success("钱包退款完成!");
                }
                order.setRefuOrderNo(weixinOrderRefuNo);
                order.setRefundStatus(((order.getPaymentKind() == JConstant.PayType.ALIPAY) ? JConstant.OrderRefundStatus.REFUNDING :
                        (order.getPaymentKind() == JConstant.PayType.WALLET  ? REFUND_SUCCESS : REFUNDSUCESS) ));//支付宝有密退款
            } else if (refundStatus == JConstant.OrderRefundStatus.REFUNDFAIL.intValue()) {//审核失败
                LOGGER.info("退款订单审核失败！");
                order.setRefundStatus(REFUNDFAIL);//支付宝有密退款
            }
            //修改退货表
            r.setAuditAdvice(auditAdvice);
            r.setAuditor(XaUtil.getCmsLoginedUserName());
            r.setAuditTime(DateUtils.getToDayStr());
            r = returnshoprecordRepository.save(r);

            //执行订单修改
            order = orderRepository.save(order);

            LOGGER.info(XaUtil.getCmsLoginedUserName() + "审核订单" + r.getOrderNo() + "退货管理");
        }

        return xr;
    }
}
